import SwiftUI
import Foundation

/*
* 面积图数据
*/
class PyrometerData{
    var text : String = "" //文字
    var key : String = "" //键
    var lastClose :Double = 0 //开始数据
    var close : Double = 0 //最新数据
    var value : Double = 0 //数值
    var location : FCPoint = FCPoint(x:0, y:0) //位置
    var size : FCSize = FCSize(cx:0, cy:0) //大小
}

/*
* 面积图
*/
class PyrometerDiv : FCView{
    override init(){
        super.init()
        super.viewType = "pyrometer"
    }
    var useAnimation : Bool = false //是否使用动画
    var INF : Double = 0x3f3f3f //无效数据
    var Rwidth : Double = 0 //宽度
    var Rheight : Double = 0 //高度
    var children = [PyrometerData]() //子视图
    var rects = [FCRect]()
}

/*
 * 面积图处理
 */
class pyrometer: FCUIView{
    /*
     * 重绘背景的实现方法
     * view:视图
     * paint:绘图对象
     * clipRect:裁剪区域
     */
    func onPaint(view:FCView, paint:FCPaint, clipRect:FCRect) {
        if view.viewType == "pyrometer"{
            let pView = view as! PyrometerDiv
            drawDiv(div:view, paint:paint, clipRect:clipRect)
            if pView.children.count > 0{
                for i in 0...pView.children.count - 1{
                    let pData = pView.children[i]
                    var backColor = "none"
                    var borderColor = "none"
                    if paint.defaultUIStyle == "dark"{
                        if pData.close >= pData.lastClose{
                            backColor = "rgb(219,68,83)"
                        }
                        else{
                            backColor = "rgb(15,193,118)"
                        }
                        borderColor = "rgb(0,0,0)"
                    }
                    else if paint.defaultUIStyle == "light"{
                        if pData.close >= pData.lastClose{
                            backColor = "rgb(255,255,255)"
                        }
                        else{
                            backColor = "rgb(255,255,255)"
                        }
                        borderColor = "rgb(255,255,255)"
                    }
                    paint.fillRect(color:backColor, left:pData.location.x, top:pData.location.y, right:pData.location.x + pData.size.cx, bottom:pData.location.y + pData.size.cy)
                    paint.drawRect(color:borderColor, width:1, style:[], left:pData.location.x, top:pData.location.y, right:pData.location.x + pData.size.cx, bottom:pData.location.y + pData.size.cy)
                    var fontSize1 = Int(min(pData.size.cx, pData.size.cy) / 5)
                    if fontSize1 > 1{
                        let baseUpper = pData.text
                        var font1 = "Default," + String(fontSize1)
                        var tSize = paint.textSize(text:baseUpper, font:font1)
                        var isContinue = false
                        while tSize.cx > pData.size.cx - 10{
                            fontSize1 = fontSize1 - 1
                            if fontSize1 < 2{
                                isContinue = true
                                break
                            }
                            font1 = "Default," + String(fontSize1)
                            tSize = paint.textSize(text:baseUpper, font:font1)
                        }
                        if isContinue{
                            continue
                        }
                        let quoteUpper = pData.key
                        let font2 = "Default," + String(fontSize1 / 2)
                        let tSize2 = paint.textSize(text:quoteUpper, font:font2)
                        if paint.defaultUIStyle == "dark"{
                            paint.drawText(text:baseUpper, color:"rgb(255,255,255)", font:font1, x:pData.location.x + (pData.size.cx - tSize.cx) / 2, y:pData.location.y + pData.size.cy / 2 - tSize.cy - tSize.cy / 2)
                            paint.drawText(text:quoteUpper, color:"rgb(255,255,255)", font:font2, x:pData.location.x + (pData.size.cx - tSize2.cx) / 2, y:pData.location.y + pData.size.cy / 2 - tSize.cy / 4)
                        }
                        else if paint.defaultUIStyle == "light"{
                            paint.drawText(text:baseUpper, color:"rgb(0,0,0)", font:font1, x:pData.location.x + (pData.size.cx - tSize.cx) / 2, y:pData.location.y + pData.size.cy / 2 - tSize.cy - tSize.cy / 2)
                            paint.drawText(text:quoteUpper, color:"rgb(0,0,0)", font:font2, x:pData.location.x + (pData.size.cx - tSize2.cx) / 2, y:pData.location.y + pData.size.cy / 2 - tSize.cy / 4)
                        }
                        var strPrice = "0.00%"
                        if pData.lastClose > 0{
                            strPrice = toFixed(value:100 * (pData.close - pData.lastClose) / pData.lastClose, digit:2) + "%"
                            if pData.close > pData.lastClose{
                                strPrice = "+" + strPrice
                            }
                        }
                        let font3 = "Default," + String(fontSize1 * 2 / 3)
                        let tSize5 = paint.textSize(text:strPrice, font:font3)
                        if paint.defaultUIStyle == "dark"{
                            paint.drawText(text:strPrice, color:"rgb(255,255,255)", font:font3, x:pData.location.x + (pData.size.cx - tSize5.cx) / 2, y:pData.location.y + pData.size.cy / 2 + tSize.cy - tSize.cy / 2)
                        }else if paint.defaultUIStyle == "light"{
                            paint.drawText(text:strPrice, color:"rgb(0,0,0)", font:font3, x:pData.location.x + (pData.size.cx - tSize5.cx) / 2, y:pData.location.y + pData.size.cy / 2 + tSize.cy - tSize.cy / 2)
                        }
                    }
                }
            }
        }
        else{
            onPaintDefault(view: view, paint: paint, clipRect: clipRect)
        }
    }
    
    /*
    * 获取长度
    */
    func rWidth(pyrometer:PyrometerDiv, R:[Double], w:Double)->Double{
        return min(pyrometer.Rwidth, pyrometer.Rheight)
    }
    
    /*
    * 获取最差的值
    */
    func worst(pyrometer:PyrometerDiv, R:[Double], w:Double)->Double{
        if R.count == 0{
            return pyrometer.INF
        }
        var rmx = 0.0
        var rmn = pyrometer.INF
        var s = 0.0
        for x in 0...R.count - 1{
            let r = R[x]
            s = s + r
            if r > rmx{
                rmx = r
            }
            if r < rmn{
                rmn = r
            }
        }
        let pw = pow(w, 2)
        let sw = pow(s, 2)
        return max(pw * rmx / sw, sw / (pw * rmn))
    }
    
    /*
    * 重置行
    */
    func layoutrow(pyrometer:PyrometerDiv, R:[Double], w:Double){
        let width = pyrometer.size.cx
        let height = pyrometer.size.cy
        var lx = width - pyrometer.Rwidth
        var ly = height - pyrometer.Rheight
        var direction = 0  
        
        var sumValue = 0.0
        for x in 0...R.count - 1{
            sumValue = sumValue + R[x]
        }
        let ext = sumValue / w
        if abs(w - pyrometer.Rwidth) <= 1e-6{
            pyrometer.Rheight = pyrometer.Rheight - ext
            direction = 0
        }else{
            pyrometer.Rwidth = pyrometer.Rwidth - ext
            direction = 1
        }
        for x in 0...R.count - 1{
            let r = R[x]
            if direction == 0{
                let hh = ext
                let ww = r / ext
                let newRect = FCRect(left:0, top:0, right:0, bottom:0)
                newRect.left = floor(lx)
                newRect.top = floor(ly)
                newRect.right = ceil(lx + ww)
                newRect.bottom = ceil(ly + hh)
                pyrometer.rects.append(newRect)
                lx = lx + ww
            }else{
                let ww = ext
                let hh = r / ext
                let newRect = FCRect(left:0, top:0, right:0, bottom:0)
                newRect.left = floor(lx)
                newRect.top = floor(ly)
                newRect.right = ceil(lx + ww)
                newRect.bottom = ceil(ly + hh)
                pyrometer.rects.append(newRect)
                ly = ly + hh
            }
        }
    }
    
    /*
    * 秒表事件
    */
    func onPyrometerTime(pyrometer:PyrometerDiv){
        var paint2 = false
        if pyrometer.useAnimation{
            if pyrometer.rects.count > 0{
                for i in 0...pyrometer.rects.count - 1{
                    let subView = pyrometer.children[i]
                    let targetRect = pyrometer.rects[i]
                    let nowRect = FCRect(left:subView.location.x, top:subView.location.y, right:subView.location.x + subView.size.cx, bottom:subView.location.y + subView.size.cy)
                    if (true) {
                        if nowRect.left > targetRect.left {
                            nowRect.left -= (nowRect.left - targetRect.left) / 4
                            if nowRect.left - targetRect.left < 10 {
                                nowRect.left = targetRect.left
                            }
                            paint2 = true
                        }
                        else if nowRect.left < targetRect.left {
                            nowRect.left += (targetRect.left - nowRect.left) / 4
                            if targetRect.left - nowRect.left < 10 {
                                nowRect.left = targetRect.left
                            }
                            paint2 = true
                        }
                    }
                    
                    if (true) {
                        if nowRect.top > targetRect.top {
                            nowRect.top -= (nowRect.top - targetRect.top) / 4
                            if nowRect.top - targetRect.top < 10 {
                                nowRect.top = targetRect.top
                            }
                            paint2 = true
                        }
                        else if nowRect.top < targetRect.top {
                            nowRect.top += (targetRect.top - nowRect.top) / 4
                            if targetRect.top - nowRect.top < 10 {
                                nowRect.top = targetRect.top
                            }
                            paint2 = true
                        }
                    }
                    
                    if (true) {
                        if nowRect.right > targetRect.right {
                            nowRect.right -= (nowRect.right - targetRect.right) / 4
                            if nowRect.right - targetRect.right < 10 {
                                nowRect.right = targetRect.right
                            }
                            paint2 = true
                        }
                        else if nowRect.right < targetRect.right {
                            nowRect.right += (targetRect.right - nowRect.right) / 4
                            if targetRect.right - nowRect.right < 10 {
                                nowRect.right = targetRect.right
                            }
                            paint2 = true
                        }
                    }
                    if (true) {
                        if nowRect.bottom > targetRect.bottom {
                            nowRect.bottom -= (nowRect.bottom - targetRect.bottom) / 4
                            if nowRect.bottom - targetRect.bottom < 10 {
                                nowRect.bottom = targetRect.bottom
                            }
                            paint2 = true
                        }
                        else if nowRect.bottom < targetRect.bottom {
                            nowRect.bottom += (targetRect.bottom - nowRect.bottom) / 4
                            if targetRect.bottom - nowRect.bottom < 10 {
                                nowRect.bottom = targetRect.bottom
                            }
                            paint2 = true
                        }
                    }
                    subView.location = FCPoint(x:nowRect.left, y:nowRect.top)
                    subView.size = FCSize(cx:nowRect.right - nowRect.left, cy:nowRect.bottom - nowRect.top)
                }
            }
        }else{
            if pyrometer.rects.count > 0{
                for i in 0...pyrometer.rects.count - 1{
                    let subView = pyrometer.children[i]
                    let targetRect = pyrometer.rects[i]
                    subView.location = FCPoint(x:targetRect.left, y:targetRect.top)
                    subView.size = FCSize(cx:targetRect.right - targetRect.left, cy:targetRect.bottom - targetRect.top)
                }
            }
        }
        if paint2{
            invalidateView(view:pyrometer)
        }
    }
    
    /*
    * 更新面积图
    */
    func updatePyromoter(pyrometer:PyrometerDiv){
        if pyrometer.children.count > 0{
            pyrometer.rects = [FCRect]()
            var totalAmount = 0.0
            for i in 0...pyrometer.children.count - 1{
                totalAmount += pyrometer.children[i].value
            }
            var rates = [Double]()
            for i in 0...pyrometer.children.count - 1{
                rates.append(pyrometer.children[i].value / totalAmount)
            }
            pyrometer.Rwidth = pyrometer.size.cx
            pyrometer.Rheight = pyrometer.size.cy
            var areas = [Double]()
            for i in 0...rates.count - 1{
                areas.append(rates[i] * pyrometer.size.cx * pyrometer.size.cy)
            }
            var children = areas
            var row = [Double]()
            var w = min(pyrometer.Rwidth, pyrometer.Rheight)
            while (true) {
                if pyrometer.rects.count > pyrometer.children.count {
                    break
                }
                if w <= 0{
                    break
                }
                if children.count == 0 {
                    if row.count > 0 {
                        layoutrow(pyrometer: pyrometer, R: row, w: w)
                    }
                    break
                }
                
                let c = children[0]
                if c == 0{
                    layoutrow(pyrometer: pyrometer, R: row, w: w)
                    break
                }
                var newrow = [Double]()
                if row.count > 0{
                    for x in 0...row.count - 1{
                        newrow.append(row[x])
                    }
                }
                newrow.append(c)
                if worst(pyrometer:pyrometer, R:row, w:w) >= worst(pyrometer:pyrometer, R:newrow, w:w) {
                    var tmp = [Double]()
                    if children.count > 0{
                        for x in 1...children.count - 1{
                            tmp.append(children[x])
                        }
                    }
                    children = tmp
                    row = newrow
                }
                else {
                    layoutrow(pyrometer: pyrometer, R: row, w: w)
                    row = [Double]()
                    w = rWidth(pyrometer:pyrometer, R:row, w:Double(Int(w)))
                }
            }
        }
    }
    
    /*
     * 更新布局
     */
    func updateView(views:[FCView]) {
        updateViewDefault(views: views)
        if views.count > 0{
            for i in 0...views.count - 1 {
                let view = views[i]
                if view.viewType == "pyrometer"{
                    updatePyromoter(pyrometer:view as! PyrometerDiv)
                    onPyrometerTime(pyrometer:view as! PyrometerDiv)
                }
            }
        }
    }
    
    let pyrometer = PyrometerDiv()
    
    /*
     * 排序
     */
    func sortPyrometerDesc(x:PyrometerData, y:PyrometerData)->Bool{
        return x.value > y.value
    }

    /*
     * 初始化布局
     */
    override func onLoad(){
        let isInit = super.gInit
        super.onLoad()
        if !isInit{
            gPaint.defaultUIStyle = "dark"
            gPaint.addPaintEvent(callBack: onPaint)
            gPaint.addUpdateViewEvent(callBack: updateView)
            pyrometer.dock = "fill"
            pyrometer.backColor = "rgb(0,0,0)"
            addView(view:pyrometer, paint:gPaint)
            let strUrl = "http://110.42.188.197:9968/quote?func=price&count=50&codes=all"
            if let url = URL(string: strUrl) {
                let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
                    if let error = error {
                        print("Error: \(error)")
                        return
                    }
                    if let result = String(data: data!, encoding: .utf8) {
                        DispatchQueue.main.async {
                            let strs = result.split(separator:"\r\n")
                            for i in 0...strs.count - 1{
                                let subStrs = strs[i].split(separator:",")
                                if subStrs.count >= 15{
                                    let pData = PyrometerData()
                                    pData.key = String(subStrs[0])
                                    pData.text = String(subStrs[1])
                                    pData.value = StringToFloat(str:String(subStrs[6]))
                                    pData.close = StringToFloat(str:String(subStrs[2]))
                                    pData.lastClose = StringToFloat(str:String(subStrs[8]))
                                    pData.size = FCSize(cx:0, cy:0)
                                    pData.location = FCPoint(x:self.pyrometer.size.cx, y:self.pyrometer.size.cy)
                                    self.pyrometer.children.append(pData)
                                }
                            }
                            self.pyrometer.children.sort(by: self.sortPyrometerDesc)
                            self.updateView(views:self.gPaint.views)
                            invalidateView(view:self.pyrometer)
                        }
                    }
                }
                task.resume()
            }
        }
    }
}
